﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;

namespace WMI.NET.CIM
{
    /// <summary>
    /// The CIM_Memory class represents the capabilities and management of memory-related logical devices.
    /// </summary>
    public class CIM_Memory : CIM_StorageExtent
    {

        private byte[] _AdditionalErrorData;
        private Nullable<Boolean> _CorrectableError;
        private Nullable<UInt64> _EndingAddress;
        private Nullable<UInt16> _ErrorAccess;
        private Nullable<UInt64> _ErrorAddress;
        private Nullable<byte> _ErrorData;
        private Nullable<UInt16> _ErrorDataOrder;
        private Nullable<UInt16> _ErrorInfo;
        private Nullable<UInt64> _ErrorResolution;
        private Nullable<DateTimeOffset> _ErrorTime;
        private Nullable<UInt32> _ErrorTransferSize;
        private string _OtherErrorDescription;
        private Nullable<UInt64> _StartingAddress;
        private Nullable<Boolean> _SystemLevelAddress;

        /// <summary>
        /// Array of octets that hold additional error information. An example is Error Checking and Correcting (ECC) Syndrome, or the return of the check bits if a CRC-based error methodology is used. In the latter case, if a single-bit error is recognized and the CRC algorithm is known, the exact bit that failed can be determined. This type of data (ECC Syndrome, check-bit or parity-bit data, or other vendor supplied information) is included in this field. If the ErrorInfo property is equal to 3 ("OK"), then this property has no meaning. 
        /// </summary>
        public byte[] AdditionalErrorData { get { return _AdditionalErrorData; } }

        /// <summary>
        /// If TRUE, the most recent error was correctable. If the ErrorInfo property is equal to 3 ("OK"), then this property has no meaning.
        /// </summary>
        public Nullable<Boolean> CorrectableError { get { return _CorrectableError; } }

        /// <summary>
        /// Ending address referenced by an application or operating system and mapped by a memory controller for this memory object. The ending address is specified in kilobytes.
        /// </summary>
        public Nullable<UInt64> EndingAddress { get { return _EndingAddress; } }

        /// <summary>
        /// Memory access operation that caused the last error. The type of error is described by the ErrorInfo property. If the ErrorInfo property is equal to 3 ("OK"), then this property has no meaning.
        /// </summary>
        public Nullable<UInt16> ErrorAccess { get { return _ErrorAccess; } } //TODO enum

        /// <summary>
        /// Address of the last memory error. The type of error is described by the ErrorInfo property. If the ErrorInfo property is equal to 3 ("OK"), then this property has no meaning.
        /// </summary>
        public Nullable<UInt64> ErrorAddress { get { return _ErrorAddress; } }

        /// <summary>
        /// Data captured during the last erroneous memory access. The data occupies the first n octets of the array that are necessary to hold the number of bits specified by the ErrorTransferSize property. If ErrorTransferSize is 0, then this property has no meaning.
        /// </summary>
        public Nullable<byte> ErrorData { get { return _ErrorData; } }

        /// <summary>
        /// Order of data stored in the ErrorData property. If ErrorTransferSize is 0, then this property has no meaning.
        /// </summary>
        public Nullable<UInt16> ErrorDataOrder { get { return _ErrorDataOrder; } } //TODO enum

        /// <summary>
        /// Type of error that occurred most recently. The values 12 through 14 are undefined in the CIM schema because DMI mixes the semantics of the error type and whether it was correctable. Whether an error is correctable is indicated in the CorrectableError property.
        /// </summary>
        public Nullable<UInt16> ErrorInfo { get { return _ErrorInfo; } }

        /// <summary>
        /// Specifies the range, in bytes, to which the last error can be resolved. For example, if error addresses are resolved to bit 11 (that is, on a typical page basis), then errors can be resolved to 4 KB boundaries and this property is set to 4000. If the ErrorInfo property is equal to 3 ("OK"), then this property has no meaning.
        /// </summary>
        public Nullable<UInt64> ErrorResolution { get { return _ErrorResolution; } }

        /// <summary>
        /// Date and time that the last memory error occurred. The type of error is described by the ErrorInfo property. If the ErrorInfo property is equal to 3 ("OK"), then this property has no meaning.
        /// </summary>
        public Nullable<DateTimeOffset> ErrorTime { get { return _ErrorTime; } }

        /// <summary>
        /// Size of the data transfer, in bits, that caused the last error. A value of 0 indicates no error. If the ErrorInfo property is equal to 3 ("OK"), then this property should be set to 0.
        /// </summary>
        public Nullable<UInt32> ErrorTransferSize { get { return _ErrorTransferSize; } }

        /// <summary>
        /// Free form string that provides information if the ErrorType property is set to 1 ("Other"). If it is not set to 1, then this string has no meaning.
        /// </summary>
        public string OtherErrorDescription { get { return _OtherErrorDescription; } }

        /// <summary>
        /// Beginning address, referenced by an application or operating system and mapped by a memory controller, for this memory object. The starting address is specified in kilobytes.
        /// </summary>
        public Nullable<UInt64> StartingAddress { get { return _StartingAddress; } }

        /// <summary>
        /// Indicates whether the address information in the ErrorAddress property is a system-level address (TRUE) or a physical address (FALSE). If the ErrorInfo property is equal to 3 ("OK"), then this property has no meaning.
        /// </summary>
        public Nullable<Boolean> SystemLevelAddress { get { return _SystemLevelAddress; } }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mbo"></param>
        public CIM_Memory(ManagementBaseObject mbo)
            :base(mbo)
        {
            _AdditionalErrorData = mbo.GetByteValueArray("AdditionalErrorData");
            _CorrectableError = mbo.GetBoolValue("CorrectableError");
            _EndingAddress = mbo.GetUlongValue("EndingAddress");
            _ErrorAccess = mbo.GetUshortValue("ErrorAccess");
            _ErrorAddress = mbo.GetUlongValue("ErrorAddress");
            _ErrorData = mbo.GetByteValue("ErrorData");
            _ErrorDataOrder = mbo.GetUshortValue("ErrorDataOrder");
            _ErrorInfo = mbo.GetUshortValue("ErrorInfo");
            _ErrorResolution = mbo.GetUlongValue("ErrorResolution");
            _ErrorTime = mbo.GetDateTimeOffsetValue("ErrorTime" , Consts.DateTimeFormat);
            _ErrorTransferSize = mbo.GetUIntValue("ErrorTransferSize");
            _OtherErrorDescription = mbo.GetStringValue("OtherErrorDescription");
            _StartingAddress = mbo.GetUlongValue("StartingAddress");
            _SystemLevelAddress = mbo.GetBoolValue("SystemLevelAddress");
        }

    }
}
